﻿using System;
using GeoAPI.Geometries;

namespace NetTopologySuite.GeometriesGraph.Index
{
	public class MonotoneChainEdge
	{
		public MonotoneChainEdge(Edge e)
		{
			this.e = e;
			this.pts = e.Coordinates;
			MonotoneChainIndexer monotoneChainIndexer = new MonotoneChainIndexer();
			this.startIndex = monotoneChainIndexer.GetChainStartIndices(this.pts);
		}

		public Coordinate[] Coordinates
		{
			get
			{
				return this.pts;
			}
		}

		public int[] StartIndexes
		{
			get
			{
				return this.startIndex;
			}
		}

		public double GetMinX(int chainIndex)
		{
			double x = this.pts[this.startIndex[chainIndex]].X;
			double x2 = this.pts[this.startIndex[chainIndex + 1]].X;
			if (x >= x2)
			{
				return x2;
			}
			return x;
		}

		public double GetMaxX(int chainIndex)
		{
			double x = this.pts[this.startIndex[chainIndex]].X;
			double x2 = this.pts[this.startIndex[chainIndex + 1]].X;
			if (x <= x2)
			{
				return x2;
			}
			return x;
		}

		public void ComputeIntersects(MonotoneChainEdge mce, SegmentIntersector si)
		{
			for (int i = 0; i < this.startIndex.Length - 1; i++)
			{
				for (int j = 0; j < mce.startIndex.Length - 1; j++)
				{
					this.ComputeIntersectsForChain(i, mce, j, si);
				}
			}
		}

		public void ComputeIntersectsForChain(int chainIndex0, MonotoneChainEdge mce, int chainIndex1, SegmentIntersector si)
		{
			this.ComputeIntersectsForChain(this.startIndex[chainIndex0], this.startIndex[chainIndex0 + 1], mce, mce.startIndex[chainIndex1], mce.startIndex[chainIndex1 + 1], si);
		}

		private void ComputeIntersectsForChain(int start0, int end0, MonotoneChainEdge mce, int start1, int end1, SegmentIntersector ei)
		{
			Coordinate p = this.pts[start0];
			Coordinate p2 = this.pts[end0];
			Coordinate p3 = mce.pts[start1];
			Coordinate p4 = mce.pts[end1];
			if (end0 - start0 == 1 && end1 - start1 == 1)
			{
				ei.AddIntersections(this.e, start0, mce.e, start1);
				return;
			}
			this.env1.Init(p, p2);
			this.env2.Init(p3, p4);
			if (!this.env1.Intersects(this.env2))
			{
				return;
			}
			int num = (start0 + end0) / 2;
			int num2 = (start1 + end1) / 2;
			if (start0 < num)
			{
				if (start1 < num2)
				{
					this.ComputeIntersectsForChain(start0, num, mce, start1, num2, ei);
				}
				if (num2 < end1)
				{
					this.ComputeIntersectsForChain(start0, num, mce, num2, end1, ei);
				}
			}
			if (num < end0)
			{
				if (start1 < num2)
				{
					this.ComputeIntersectsForChain(num, end0, mce, start1, num2, ei);
				}
				if (num2 < end1)
				{
					this.ComputeIntersectsForChain(num, end0, mce, num2, end1, ei);
				}
			}
		}

		private readonly Edge e;

		private readonly Coordinate[] pts;

		private readonly int[] startIndex;

		private readonly Envelope env1 = new Envelope();

		private readonly Envelope env2 = new Envelope();
	}
}
